package sql_builder

import (
	"fmt"
	"reflect"
	"strings"
	"time"
)

type SqlBuilder struct {
	tableName string
}

func NewSqlBuilder(tableName string) *SqlBuilder {
	return &SqlBuilder{tableName: tableName}
}

func (this *SqlBuilder) SetSql(value interface{}) string {
	object := reflect.ValueOf(value)
	var elem reflect.Value
	if object.Kind() == reflect.Ptr {
		elem = object.Elem()
	} else {
		elem = object
	}
	typeOfType := elem.Type()
	numField := elem.NumField()
	fieldNameArray := make([]string, numField)
	fieldValueArray := make([]interface{}, numField)
	for i := 0; i < numField; i++ {
		field := elem.Field(i)
		fieldNameArray[i] = this.handleFieldName(typeOfType.Field(i).Name)
		fieldValueArray[i] = field.Interface()
	}

	sql := "INSERT INTO `" + this.tableName + "`(" + this.fieldNameListPart(fieldNameArray, numField) +
		") VALUES(" + this.insertValuesPart(fieldValueArray, numField) +
		") ON DUPLICATE KEY UPDATE " + this.updateValuesPart(fieldNameArray, numField)

	return sql
}

func (this *SqlBuilder) DelSql(id int64) string {
	sql := fmt.Sprintf("DELETE FROM `%s` where id=%d", this.tableName, id)
	return sql
}

/**
处理单引号
*/
func (this *SqlBuilder) handleSingleQuotes(value string) string {
	return strings.ReplaceAll(value, "'", "\\'")
}

func (this *SqlBuilder) handleFieldName(fieldName string) string {
	bytes := []byte(fieldName)
	length := len(bytes)
	var partArray []string
	previousIndex := 0
	for i := 1; i < length; i++ {
		theByte := bytes[i]
		if theByte >= 'A' && theByte <= 'Z' {
			partArray = append(partArray, fieldName[previousIndex:i])
			previousIndex = i
		}
	}
	partArray = append(partArray, fieldName[previousIndex:length])
	arrayCount := len(partArray)

	var result string
	result += partArray[0]
	for i := 1; i < arrayCount; i++ {
		if len(result) > 0 {
			result += "_"
		}
		result += partArray[i]
	}
	return strings.ToLower(result)
}

func (this *SqlBuilder) fieldNameListPart(fieldNameArray []string, count int) string {
	var result string
	for i := 0; i < count; i++ {
		if len(result) > 0 {
			result += ","
		}
		result += "`" + fieldNameArray[i] + "`"
	}
	return result
}

func (this *SqlBuilder) handleInsertValue(value interface{}) string {
	theType := reflect.TypeOf(value).String()
	switch theType {
	case "time.Time":
		return "'" + value.(time.Time).Format("2006-01-02 15:04:05.999") + "'"
	case "string":
		return "'" + this.handleSingleQuotes(value.(string)) + "'"
	default:
		return fmt.Sprintf("%v", value)
	}
}

func (this *SqlBuilder) insertValuesPart(fieldValueArray []interface{}, count int) string {
	var result string
	for i := 0; i < count; i++ {
		if len(result) > 0 {
			result += ","
		}
		result += this.handleInsertValue(fieldValueArray[i])
	}
	return result
}

func (this *SqlBuilder) updateValuesPart(fieldNameArray []string, count int) string {
	var result string
	for i := 0; i < count; i++ {
		if len(result) > 0 {
			result += ","
		}
		fieldName := fieldNameArray[i]
		result += "`" + fieldName + "`=VALUES(`" + fieldName + "`)"
	}
	return result
}
